import {Client, Room} from "colyseus";
import {MapSchema, Schema, type} from "@colyseus/schema";
import {distance, randomChineseName, randomColor, simpleCollisionDetection} from "../Utils";
import {Setting} from "../Setting";
import {Bullet, Player} from "../Schema/Player";

// Our custom game state, an ArraySchema of type Player only at the moment
export class State extends Schema {
    @type({map: Player})
    players = new MapSchema<Player>();
}

export class GameRoom extends Room {

    constructor() {
        super();
        this.maxClients = 8;
    }

    // When room is initialized
    onCreate(options: any) {
        // initialize empty room state
        this.setState(new State());

        this.onMessage("action", (client, message) => {
            // broadcast a message to all clients
            this.broadcast("action-taken", "an action has been taken!");
        });

        this.onMessage("fire", (client, data) => {
            // sends "fire" event to every client, except the one who triggered it.
            // this.broadcast("fire", message, {except: client});

            const player = this.state.players.get(client.sessionId);
            if (!player.active) return;
            let dir = player.dir;

            let b_x = player.x + player.w / 2;
            let b_y = player.y + player.h / 2;
            let offset = Math.max(player.w, player.h);
            // 修正发射位置位置
            switch (dir) {
                case 0: b_y -= offset;  break;
                case 1: b_x -= offset;  break;
                case 2: b_y += offset;  break;
                case 3: b_x += offset;  break;
            }
            // create a bullet
            let bullet = new Bullet();
            bullet.x = b_x;
            bullet.y = b_y;
            player.bullets.push(bullet);

            let c = 0;
            let clientId = client.sessionId;
            let interval = setInterval(() => {
                if (c >= 60 || bullet.x < 0 || bullet.x > Setting.width || bullet.y < 0 || bullet.y > Setting.height) {
                    player.bullets.shift();
                    console.log(player.id, 'remove bullet', player.bullets.length);
                    clearInterval(interval);
                    return;
                }
                // 推演子弹飞行
                switch (dir) {
                    case 0: bullet.y -= bullet.speed;   break;
                    case 1: bullet.x -= bullet.speed;   break;
                    case 2: bullet.y += bullet.speed;   break;
                    case 3: bullet.x += bullet.speed;   break;
                }

                // simple碰撞检测
                let players = this.state.players;
                players.forEach((p: Player, key: string) => {
                    // 针对非发射玩家
                    if (key !== clientId && p.active) {
                        let pc_x = p.x + p.w / 2;
                        let pc_y = p.y + p.h / 2;

                        if (simpleCollisionDetection(pc_x, pc_y, bullet.x, bullet.y, Math.max(p.w, p.h) / 2)) {
                            console.log('simple_detection', player.name, '->' , p.name);
                            p.hp -= bullet.damage;

                            // 移除子弹
                            player.bullets.shift();
                            console.log(player.name, 'remove bullet', player.bullets.length);
                            // 死亡状态
                            if (p.hp <= 0) {
                                p.active = false;
                                console.log(player.name, 'death');
                            }
                            clearInterval(interval);
                        }
                    }
                });
                c++;
            }, 33);
        });

        // Called every time this room receives a "move" message
        this.onMessage("move", (client, data) => {
            const player = this.state.players.get(client.sessionId);
            player.dir = data.dir;

            // 触边掉头
            if (player.y < 10) {
                player.dir = 2;
            } else if (player.x < 10) {
                player.dir = 3;
            } else if (player.x > Setting.width - 60) {
                player.dir = 1;
            } else if (player.y > Setting.height - 60) {
                player.dir = 0;
            }

            // 前进
            switch (player.dir) {
                case 0:
                    player.y -= player.speed;
                    break;
                case 1:
                    player.x -= player.speed;
                    break;
                case 2:
                    player.y += player.speed;
                    break;
                case 3:
                    player.x += player.speed;
                    break;
            }

            console.log(client.sessionId + " at, x: " + player.x, "y: " + player.y);
        });

        this.onMessage("*", (client, type, message) => {
            // Triggers when any other type of message is sent,
            // excluding "action", which has its own specific handler defined above.
            console.log(client.sessionId, "sent", type, message);
        });
    }

    // Authorize client based on provided options before WebSocket handshake is complete
    // onAuth(client: Client, options: any, request: http.IncomingMessage) {
    // }

    // When client successfully join the room
    onJoin(client: Client, options: any, auth: any) {
        let player = new Player();
        player.color = randomColor();
        player.name = randomChineseName();
        player.id = client.sessionId;
        this.state.players.set(client.sessionId, player);
    }

    // When a client leaves the room
    onLeave(client: Client, consented: boolean) {
        if (this.state.players.has(client.sessionId)) {
            this.state.players.delete(client.sessionId);
        }
    }

    // Cleanup callback, called after there are no more clients in the room. (see `autoDispose`)
    onDispose() {
    }
}